﻿using System;
using System.Text;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace MyLibrary.IO.TextParser
{
	#region 定数定義
	/// <summary>
	/// 改行コード定義クラス
	/// </summary>
	public class LineBreakType
	{
		public const string CrLf = "\r\n";
		public const string Cr = "\r";
		public const string Lf = "\n";
	}

	/// <summary>
	/// 記号定義クラス
	/// </summary>
	public class SymbolType
	{
		public const string Comma = ",";
		public const string Tab = "\t";
		public const string Equal = "=";
		public const string Colon = ":";
		public const string Semicolon = ";";
		public const string Sharp = "#";
	}
	#endregion

	#region パーサ
	/// <summary>
	/// コンフィグパーサクラス
	/// (iniファイルエンティティクラス)
	/// </summary>
	public class ConfigParser : IDisposable, IList<ConfigSection>, IDictionary<string, ConfigSection>
	{
		#region 定数定義
		/// <summary>
		/// デフォルトエンコーディング
		/// </summary>
		public readonly Encoding DEFAULT_ENCODING = Encoding.GetEncoding("Shift_JIS");
		#endregion

		#region プロパティ
		/// <summary>
		/// ファイルパス
		/// </summary>
		public string Path { get; protected set; }

		/// <summary>
		/// エンコーディング
		/// </summary>
		public Encoding Encoding { get; protected set; }

		/// <summary>
		/// パース時の現在行
		/// </summary>
		public int LineNumber { get; protected set; }

		#region 改行コード
		/// <summary>
		/// 改行コードの実体
		/// </summary>
		protected string _LineBreak = LineBreakType.CrLf;

		/// <summary>
		/// 改行コード
		/// </summary>
		public string LineBreak
		{
			get { return _LineBreak; }
			set { _LineBreak = value; }
		}
		#endregion

		#region デリミタ
		/// <summary>
		/// デリミタの実体
		/// </summary>
		protected string _Delimiter = SymbolType.Equal;

		/// <summary>
		/// デリミタ
		/// </summary>
		public string Delimiter
		{
			get { return _Delimiter; }
			set { _Delimiter = value; }
		}
		#endregion

		#region コメント記号
		/// <summary>
		/// コメント記号の実体
		/// </summary>
		protected string _CommentSymbol = SymbolType.Semicolon;

		/// <summary>
		/// コメント記号
		/// </summary>
		public string CommentSymbol
		{
			get { return _CommentSymbol; }
			set { _CommentSymbol = value; }
		}
		#endregion
		#endregion

		#region インスタンス変数定義
		/// <summary>
		/// ファイルリーダ
		/// </summary>
		protected TextReader Reader = TextReader.Null;

		/// <summary>
		/// ファイルライタ
		/// </summary>
		protected TextWriter Writer = TextWriter.Null;

		/// <summary>
		/// セクションリスト
		/// </summary>
		protected List<ConfigSection> Sections = new List<ConfigSection>();

		/// <summary>
		/// 順序リスト
		/// </summary>
		protected List<string> Order = new List<string>();
		#endregion

		#region コンストラクタ
		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="stream">ファイルストリーム</param>
		public ConfigParser(Stream stream)
		{
			Path = (stream as FileStream).Name;
			Encoding = DEFAULT_ENCODING;
			using (Reader = new StreamReader(stream, Encoding)) Parse();
		}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="stream">ファイルストリーム</param>
		/// <param name="encoding">エンコーディング</param>
		public ConfigParser(Stream stream, Encoding encoding)
		{
			Path = (stream as FileStream).Name;
			Encoding = encoding;
			using (Reader = new StreamReader(stream, Encoding)) Parse();
		}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="path">ファイルパス</param>
		public ConfigParser(string path)
		{
			Path = path;
			Encoding = DEFAULT_ENCODING;

            if (!File.Exists(Path))
            {
                File.WriteAllText(Path, "");
            }
            else
            {
                using (Reader = new StreamReader(Path, Encoding)) Parse();
            }
		}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="path">ファイルパス</param>
		/// <param name="encoding">エンコーディング</param>
		public ConfigParser(string path, Encoding encoding)
		{
            Path = System.IO.Path.GetDirectoryName(
                   System.Reflection.Assembly.GetEntryAssembly().Location) + "\\" + path;
			Encoding = encoding;

            if (!File.Exists(Path))
            {
                File.WriteAllText(Path, "");
            }
            else
            {
                using (Reader = new StreamReader(Path, Encoding)) Parse();
            }
		}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="stream">ファイルストリーム</param>
		public ConfigParser(TextReader reader)
		{
			var streamReader = reader as StreamReader;
			Path = (streamReader.BaseStream as FileStream).Name;
			Encoding = streamReader.CurrentEncoding;
			using (Reader = streamReader) Parse();
		}
		#endregion

		#region パース
		/// <summary>
		/// パース
		/// </summary>
		public void Parse()
		{
			var section = new ConfigSection(this, string.Empty);
			var comments = new List<ConfigParameter>();

			LineNumber = 0;
			string line = null;

			while ((line = Reader.ReadLine()) != null)
			{
				LineNumber += 1;

				var trimed = line.Trim();

				if (trimed.StartsWith("[") && trimed.EndsWith("]"))
				{
					Add(section.Name, section);
					section = new ConfigSection(this, line);

					if (comments.Count > 0)
					{
						section.Comments.AddRange(comments);
						comments = new List<ConfigParameter>();
					}
				}
				else
				{
					var parameter = new ConfigParameter(this, line);

					// 今回のパラメータはコメント行だった
					if (parameter.IsCommentLine)
					{
						comments.Add(parameter);
					}
					// コメントリストにコメントが入っている
					else if (comments.Count > 0)
					{
						section.AddRange(comments);
						section.Add(parameter);
						comments = new List<ConfigParameter>();
					}
					else
					{
						section.Add(parameter);
					}
				}
			}

			Add(section.Name, section);
			return;
		}
		#endregion

		#region 永続化
		/// <summary>
		/// 永続化します
		/// </summary>
		public void Save()
		{
			var buf = this.ToString();

			using (Writer = new StreamWriter(Path, false, Encoding, buf.Length))
			{
				Writer.Write(buf);
			}
		}
		#endregion

		#region 文字列化
		/// <summary>
		/// 現在のiniフォーマットを表す文字列を返します  
		/// </summary>
		/// <returns>現在のiniフォーマットを表す文字列</returns>
		public override string ToString()
		{
			var list = new List<string>();

			foreach (var section in Sections) {
				if (section.Count == 0) continue;
				list.Add(section.ToString()); 
			}

			return string.Join(LineBreak, list.ToArray()) + LineBreak;
		}
		#endregion

		#region IDisposable メンバ
		/// <summary>
		/// アンマネージリソースの解放および、リセットに関連付けられているアプリケーション定義のタスクを実行します
		/// </summary>
		public void Dispose()
		{
			if (Reader != null) Reader.Dispose();
			if (Writer != null) Writer.Dispose();
		}
		#endregion

		#region IList<ConfigSection> メンバ
		/// <summary>
		/// リスト内での指定した項目のインデックスを調べます
		/// </summary>
		/// <param name="item">リスト内で検索するオブジェクト</param>
		/// <returns>リストに存在する場合は item のインデックス。それ以外の場合は -1</returns>
		public int IndexOf(ConfigSection item)
		{
			return Sections.IndexOf(item);
		}

		/// <summary>
		/// リストの指定したインデックス位置に項目を挿入します
		/// </summary>
		/// <param name="index">item を挿入する位置のインデックス</param>
		/// <param name="item">リストに挿入するオブジェクト</param>
		public void Insert(int index, ConfigSection item)
		{
			Sections.Insert(index, item);
		}

		/// <summary>
		/// 指定したインデックス位置の項目を削除します
		/// </summary>
		/// <param name="index">削除する項目のインデックス</param>
		public void RemoveAt(int index)
		{
			Sections.RemoveAt(index);
		}

		/// <summary>
		/// 指定したインデックスにある要素を取得または設定します
		/// </summary>
		/// <param name="index">取得または設定する要素のインデックス</param>
		/// <returns>指定したインデックスにある要素</returns>
		public ConfigSection this[int index]
		{
			get
			{
				return Sections[index];
			}
			set
			{
				Sections[index] = value;
			}
		}
		#endregion

		#region ICollection<ConfigSection> メンバ
		/// <summary>
		/// コレクションに項目を追加します
		/// </summary>
		/// <param name="item">コレクションに追加するオブジェクト</param>
		public void Add(ConfigSection item)
		{
			Add(item.Name, item);
		}

		/// <summary>
		/// コレクションからすべての項目を削除します
		/// </summary>
		public void Clear()
		{
			Sections.Clear();
			Order.Clear();
		}

		/// <summary>
		/// コレクションに特定の値が格納されているかどうかを判断します
		/// </summary>
		/// <param name="item">コレクション内で検索するオブジェクト</param>
		/// <returns>item がコレクションに存在する場合は true。それ以外の場合は false</returns>
		public bool Contains(ConfigSection item)
		{
			return Sections.Contains(item);
		}

		/// <summary>
		/// コレクションの要素を配列にコピーします。配列の特定のインデックスからコピーが開始されます
		/// </summary>
		/// <param name="array">コレクションから要素がコピーされる1次元の配列</param>
		/// <param name="arrayIndex">コピーの開始位置となるインデックス</param>
		public void CopyTo(ConfigSection[] array, int arrayIndex)
		{
			Sections.CopyTo(array, arrayIndex);
		}

		/// <summary>
		/// コレクションに格納されている要素の数を取得します
		/// </summary>
		public int Count
		{
			get { return Sections.Count; }
		}

		/// <summary>
		/// コレクションが読み取り専用かどうかを示す値を取得します 
		/// </summary>
		public bool IsReadOnly
		{
			get { return false; }
		}

		/// <summary>
		/// コレクション内で最初に見つかった特定のオブジェクトを削除します
		/// </summary>
		/// <param name="item">コレクションから削除するオブジェクト</param>
		/// <returns>
		/// item がコレクションから正常に削除された場合は true。
		/// それ以外の場合は false。
		/// このメソッドは、item が元のコレクションに見つからない場合にも false を返します。
		/// </returns>
		public bool Remove(ConfigSection item)
		{
			var sections = Sections;
			var order = Order;

			try
			{
				return Sections.Remove(item) && Order.Remove(item.Name);
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);

				Sections = sections;
				Order = order;
			}

			return false;
		}
		#endregion

		#region IEnumerable<ConfigSection> メンバ
		/// <summary>
		/// コレクションを反復処理する列挙子を返します
		/// </summary>
		/// <returns>コレクションを反復処理するために使用できる IEnumerator オブジェクト</returns>
		public IEnumerator<ConfigSection> GetEnumerator()
		{
			return Sections.GetEnumerator();
		}
		#endregion

		#region IEnumerable メンバ
		/// <summary>
		/// コレクションを反復処理する列挙子を返します
		/// </summary>
		/// <returns>コレクションを反復処理するために使用できる IEnumerator オブジェクト</returns>
		IEnumerator IEnumerable.GetEnumerator()
		{
			return Sections.GetEnumerator();
		}
		#endregion

		#region IDictionary<string,ConfigSection> メンバ
		/// <summary>
		/// 指定したキーおよび値を持つ要素を IDictionary に追加します
		/// </summary>
		/// <param name="key">追加する要素のキーとして使用するオブジェクト</param>
		/// <param name="value">追加する要素の値として使用するオブジェクト</param>
		public void Add(string key, ConfigSection value)
		{
			Sections.Add(value);
			Order.Add(key);
		}

		/// <summary>
		/// 指定したキーの要素が IDictionary に格納されているかどうかを確認します
		/// </summary>
		/// <param name="key">IDictionary 内で検索されるキー</param>
		/// <returns>指定したキーを持つ要素を IDictionary が保持している場合は true。それ以外の場合は false</returns>
		public bool ContainsKey(string key)
		{
			return Order.Contains(key);
		}

		/// <summary>
		/// IDictionary のキーを保持している ICollection を取得します。 
		/// </summary>
		public ICollection<string> Keys
		{
			get { return Order; }
		}

		/// <summary>
		/// 指定したキーを持つ要素を IDictionary から削除します
		/// </summary>
		/// <param name="key">削除する要素のキー</param>
		/// <returns>
		/// 要素が正常に削除された場合は true。
		/// それ以外の場合は false。
		/// このメソッドは、key が元の IDictionary に見つからなかった場合にも false を返します
		/// </returns>
		public bool Remove(string key)
		{
			Sections.RemoveAt(Array.IndexOf(Order.ToArray(), key));
			return Order.Remove(key);
		}

		/// <summary>
		/// 指定したキーに関連付けられている値を取得します
		/// </summary>
		/// <param name="key">値を取得する対象のキー</param>
		/// <param name="value">
		/// このメソッドが返されるときに、キーが見つかった場合は、指定したキーに関連付けられている値。
		/// それ以外の場合は value パラメータの型に対する既定の値。このパラメータは初期化せずに渡されます
		/// </param>
		/// <returns>指定したキーを持つ要素が IDictionary を実装するオブジェクトに格納されている場合は true。それ以外の場合は false</returns>
		public bool TryGetValue(string key, out ConfigSection value)
		{
			//if (Order.Contains(key))
			throw new NotImplementedException();
		}

		/// <summary>
		/// IDictionary 内の値を格納している ICollection を取得します。 
		/// </summary>
		public ICollection<ConfigSection> Values
		{
			get { return Sections; }
		}

		/// <summary>
		/// 指定したキーを持つ要素を取得または設定します 
		/// </summary>
		/// <param name="key">取得または設定する要素のキー</param>
		/// <returns>指定したキーを持つ要素</returns>
		public ConfigSection this[string key]
		{
			get
			{
				var i = IndexOf(key);

				if (i < 0)
				{
					Add(new ConfigSection(this) { Name = key });
					i = Count - 1;
				}

				return Sections[i];
			}
			set
			{
				var i = IndexOf(key);

				if (i < 0)
				{
					Add(new ConfigSection(this) { Name = key });
					i = Count - 1;
				}

				Sections[i] = value;
			}
		}
		#endregion

		/// <summary>
		/// リスト内での指定した項目のインデックスを調べます
		/// </summary>
		/// <param name="key"></param>
		/// <returns>リストに存在する場合は item のインデックス。それ以外の場合は -1</returns>
		public int IndexOf(string key)
		{
			return Array.IndexOf(Order.ToArray(), key);
		}

		#region ICollection<KeyValuePair<string,ConfigSection>> メンバ
		public void Add(KeyValuePair<string, ConfigSection> item)
		{
			throw new NotImplementedException();
		}

		public bool Contains(KeyValuePair<string, ConfigSection> item)
		{
			throw new NotImplementedException();
		}

		public void CopyTo(KeyValuePair<string, ConfigSection>[] array, int arrayIndex)
		{
			throw new NotImplementedException();
		}

		public bool Remove(KeyValuePair<string, ConfigSection> item)
		{
			throw new NotImplementedException();
		}
		#endregion

		#region IEnumerable<KeyValuePair<string,ConfigSection>> メンバ
		/// <summary>
		/// コレクションを反復処理する列挙子を返します
		/// </summary>
		/// <returns>コレクションを反復処理するために使用できる IEnumerator オブジェクト</returns>
		IEnumerator<KeyValuePair<string, ConfigSection>> IEnumerable<KeyValuePair<string, ConfigSection>>.GetEnumerator()
		{
			throw new NotImplementedException();
		}
		#endregion
	}
	#endregion

	#region セクション
	/// <summary>
	/// セクションエンティティクラス
	/// </summary>
	public class ConfigSection : IList<ConfigParameter>, IDictionary<string, ConfigParameter>
	{
		#region プロパティ
		#region 実体
		/// <summary>
		/// セクション行の実体
		/// </summary>
		private string _line = string.Empty;

		/// <summary>
		/// セクション行
		/// </summary>
		public string Line
		{
			get
			{
				return IsUpdate ? string.Format("[{0}]", Name) : this._line;
			}
			protected set
			{
				this._line = value;
				IsUpdate = false;
				Parse();
			}
		}
		#endregion

		#region セクション名
		/// <summary>
		/// セクション名の実体
		/// </summary>
		private string _name = string.Empty;

		/// <summary>
		/// セクション名
		/// </summary>
		public string Name
		{
			get { return this._name; }
			set { this._name = value; IsUpdate = true; }
		}
		#endregion

		#region 更新フラグ
		/// <summary>
		/// 更新フラグの実体
		/// </summary>
		private bool _isUpdate = false;

		/// <summary>
		/// 更新されているかどうか
		/// </summary>
		public bool IsUpdate
		{
			get { return this._isUpdate; }
			protected set { this._isUpdate = value; }
		}
		#endregion
		#endregion

		#region インスタンス変数定義
		/// <summary>
		/// パーサ
		/// </summary>
		protected ConfigParser Parser;

		/// <summary>
		/// 順序リスト
		/// </summary>
		protected List<string> Order = new List<string>();

		/// <summary>
		/// パラメータリスト
		/// </summary>
		public List<ConfigParameter> Parameters = new List<ConfigParameter>();

		/// <summary>
		/// コメントリスト
		/// </summary>
		public List<ConfigParameter> Comments = new List<ConfigParameter>();
		#endregion

		#region コンストラクタ
		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="parser">パーサ</param>
		public ConfigSection(ConfigParser parser)
		{
			Parser = parser;
		}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="parser">パーサ</param>
		/// <param name="section">セクション行データ</param>
		public ConfigSection(ConfigParser parser, string line)
		{
			Parser = parser;
			Line = line;
		}
		#endregion

		#region パース
		/// <summary>
		/// パース
		/// </summary>
		public void Parse()
		{
			var trimed = Line.Trim();

			if (trimed.Length < "[]".Length) return;

			Name = trimed.Substring("[".Length, trimed.Length - ("]".Length + 1));
		}
		#endregion

		#region 文字列化
		/// <summary>
		/// 現在のセクションを表す文字列を返します  
		/// </summary>
		/// <returns>現在のセクションを表す文字列</returns>
		public override string ToString()
		{
			var list = new List<string>();

			foreach (var comment in Comments) list.Add(comment.ToString());

			if (Name.Length > 0) list.Add(Line);

			foreach (var param in Parameters) list.Add(param.ToString());

			return string.Join(Parser.LineBreak, list.ToArray());
		}
		#endregion

		#region IList<ConfigParameter> メンバ
		/// <summary>
		/// リスト内での指定した項目のインデックスを調べます
		/// </summary>
		/// <param name="item">リスト内で検索するオブジェクト</param>
		/// <returns>リストに存在する場合は item のインデックス。それ以外の場合は -1</returns>
		public int IndexOf(ConfigParameter item)
		{
			return Parameters.IndexOf(item);
		}

		/// <summary>
		/// リストの指定したインデックス位置に項目を挿入します
		/// </summary>
		/// <param name="index">item を挿入する位置のインデックス</param>
		/// <param name="item">リストに挿入するオブジェクト</param>
		public void Insert(int index, ConfigParameter item)
		{
			Parameters.Insert(index, item);
			Order.Insert(index, item.Key);
		}

		/// <summary>
		/// 指定したインデックス位置の項目を削除します
		/// </summary>
		/// <param name="index">削除する項目のインデックス</param>
		public void RemoveAt(int index)
		{
			Parameters.RemoveAt(index);
			Order.RemoveAt(index);
		}

		/// <summary>
		/// 指定したインデックスにある要素を取得または設定します
		/// </summary>
		/// <param name="index">取得または設定する要素のインデックス</param>
		/// <returns>指定したインデックスにある要素</returns>
		public ConfigParameter this[int index]
		{
			get
			{
				return Parameters[index];
			}
			set
			{
				Parameters[index] = value;
				Order[index] = value.Key;
			}
		}
		#endregion

		/// <summary>
		/// 指定したコレクションの要素をパラメータリストの末尾に追加します
		/// </summary>
		/// <param name="collection">コレクション</param>
		public void AddRange(IEnumerable<ConfigParameter> collection)
		{
			foreach (var item in collection) Add(item);
		}

		#region ICollection<ConfigParameter> メンバ
		/// <summary>
		/// コレクションに項目を追加します
		/// </summary>
		/// <param name="item">コレクションに追加するオブジェクト</param>
		public void Add(ConfigParameter item)
		{
			Add(item.Key, item);
		}

		/// <summary>
		/// コレクションからすべての項目を削除します
		/// </summary>
		public void Clear()
		{
			Parameters.Clear();
			Order.Clear();
			Comments.Clear();
		}

		/// <summary>
		/// コレクションに特定の値が格納されているかどうかを判断します
		/// </summary>
		/// <param name="item">コレクション内で検索するオブジェクト</param>
		/// <returns>item がコレクションに存在する場合は true。それ以外の場合は false</returns>
		public bool Contains(ConfigParameter item)
		{
			return Parameters.Contains(item);
		}

		/// <summary>
		/// コレクションの要素を配列にコピーします。配列の特定のインデックスからコピーが開始されます
		/// </summary>
		/// <param name="array">コレクションから要素がコピーされる1次元の配列</param>
		/// <param name="arrayIndex">コピーの開始位置となるインデックス</param>
		public void CopyTo(ConfigParameter[] array, int arrayIndex)
		{
			Parameters.CopyTo(array, arrayIndex);

			var list = new List<string>();

			foreach (var param in array) list.Add(param.Key);

			Order.CopyTo(list.ToArray(), arrayIndex);
		}

		/// <summary>
		/// コレクションに格納されている要素の数を取得します
		/// </summary>
		public int Count
		{
			get { return Parameters.Count; }
		}

		/// <summary>
		/// コレクションが読み取り専用かどうかを示す値を取得します
		/// </summary>
		public bool IsReadOnly
		{
			get { return false; }
		}

		/// <summary>
		/// コレクション内で最初に見つかった特定のオブジェクトを削除します
		/// </summary>
		/// <param name="item">コレクションから削除するオブジェクト</param>
		/// <returns>
		/// item がコレクションから正常に削除された場合は true。
		/// それ以外の場合は false。
		/// このメソッドは、item が元のコレクションに見つからない場合にも false を返します。
		/// </returns>
		public bool Remove(ConfigParameter item)
		{
			var parameters = Parameters;
			var order = Order;

			try
			{
				return Parameters.Remove(item) && Order.Remove(item.Key);
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);

				Parameters = parameters;
				Order = order;
			}

			return false;
		}
		#endregion

		#region IEnumerable<ConfigParameter> メンバ
		/// <summary>
		/// コレクションを反復処理する列挙子を返します
		/// </summary>
		/// <returns>コレクションを反復処理するために使用できる IEnumerator オブジェクト</returns>
		public IEnumerator<ConfigParameter> GetEnumerator()
		{
			return Parameters.GetEnumerator();
		}
		#endregion

		#region IEnumerable メンバ
		/// <summary>
		/// コレクションを反復処理する列挙子を返します
		/// </summary>
		/// <returns>コレクションを反復処理するために使用できる IEnumerator オブジェクト</returns>
		IEnumerator IEnumerable.GetEnumerator()
		{
			return Parameters.GetEnumerator();
		}
		#endregion

		#region IDictionary<string,ConfigParameter> メンバ
		/// <summary>
		/// 指定したキーおよび値を持つ要素を IDictionary に追加します
		/// </summary>
		/// <param name="key">追加する要素のキーとして使用するオブジェクト</param>
		/// <param name="value">追加する要素の値として使用するオブジェクト</param>
		public void Add(string key, ConfigParameter value)
		{
			Parameters.Add(value);
			Order.Add(key);
		}

		/// <summary>
		/// 指定したキーの要素が IDictionary に格納されているかどうかを確認します
		/// </summary>
		/// <param name="key">IDictionary 内で検索されるキー</param>
		/// <returns>指定したキーを持つ要素を IDictionary が保持している場合は true。それ以外の場合は false</returns>
		public bool ContainsKey(string key)
		{
			return Order.Contains(key);
		}

		/// <summary>
		/// IDictionary のキーを保持している ICollection を取得します。 
		/// </summary>
		public ICollection<string> Keys
		{
			get { return Order; }
		}

		/// <summary>
		/// 指定したキーを持つ要素を IDictionary から削除します
		/// </summary>
		/// <param name="key">削除する要素のキー</param>
		/// <returns>
		/// 要素が正常に削除された場合は true。
		/// それ以外の場合は false。
		/// このメソッドは、key が元の IDictionary に見つからなかった場合にも false を返します
		/// </returns>
		public bool Remove(string key)
		{
			Parameters.RemoveAt(IndexOf(key));
			return Order.Remove(key);
		}

		/// <summary>
		/// 指定したキーに関連付けられている値を取得します
		/// </summary>
		/// <param name="key">値を取得する対象のキー</param>
		/// <param name="value">
		/// このメソッドが返されるときに、キーが見つかった場合は、指定したキーに関連付けられている値。
		/// それ以外の場合は value パラメータの型に対する既定の値。このパラメータは初期化せずに渡されます
		/// </param>
		/// <returns>指定したキーを持つ要素が IDictionary を実装するオブジェクトに格納されている場合は true。それ以外の場合は false</returns>
		public bool TryGetValue(string key, out ConfigParameter value)
		{
			// TODO: まともな実装

			try
			{
				value = this[key];

				return true;
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);

				value = null;

				return false;
			}
		}

		/// <summary>
		/// IDictionary 内の値を格納している ICollection を取得します。 
		/// </summary>
		public ICollection<ConfigParameter> Values
		{
			get { return Parameters; }
		}

		/// <summary>
		/// 指定したキーを持つ要素を取得または設定します 
		/// </summary>
		/// <param name="key">取得または設定する要素のキー</param>
		/// <returns>指定したキーを持つ要素</returns>
		public ConfigParameter this[string key]
		{
			get { return Parameters[GetIndex(key)]; }
			set { Parameters[GetIndex(key)] = value; }
		}
		#endregion

		/// <summary>
		/// リスト内での指定した項目のインデックスを調べます
		/// </summary>
		/// <param name="key"></param>
		/// <returns>リストに存在する場合は item のインデックス。それ以外の場合は -1</returns>
		public int IndexOf(string key)
		{
			return Array.IndexOf(Order.ToArray(), key);
		}

		/// <summary>
		/// リスト内での指定した項目のインデックスを取得します
		/// リストに存在しない場合は自動的に空行パラメータの前に挿入されます 
		/// </summary>
		/// <param name="key"></param>
		/// <returns>item のインデックス</returns>
		private int GetIndex(string key)
		{
			var i = IndexOf(key);

			if (i < 0)
			{
				var param = new ConfigParameter(Parser) { Key = key };

				// TODO: 空行前に挿入
				//for (i = Count - 1; i >= 0; i--)
				//{
				//    if (Parameters[i].IsEmptyLine) continue;

				//    Insert(i, param);
				//    break;
				//}

				// TODO: 空行前挿入実装後に削除
				{
					Add(param);
					i = Count - 1;
				}
			}

			return i;
		}

		#region ICollection<KeyValuePair<string,ConfigParameter>> メンバ
		public void Add(KeyValuePair<string, ConfigParameter> item)
		{
			throw new NotImplementedException();
		}

		public bool Contains(KeyValuePair<string, ConfigParameter> item)
		{
			throw new NotImplementedException();
		}

		public void CopyTo(KeyValuePair<string, ConfigParameter>[] array, int arrayIndex)
		{
			throw new NotImplementedException();
		}

		public bool Remove(KeyValuePair<string, ConfigParameter> item)
		{
			throw new NotImplementedException();
		}

		#endregion

		#region IEnumerable<KeyValuePair<string,ConfigParameter>> メンバ
		/// <summary>
		/// コレクションを反復処理する列挙子を返します
		/// </summary>
		/// <returns>コレクションを反復処理するために使用できる IEnumerator オブジェクト</returns>
		IEnumerator<KeyValuePair<string, ConfigParameter>> IEnumerable<KeyValuePair<string, ConfigParameter>>.GetEnumerator()
		{
			throw new NotImplementedException();
		}
		#endregion
	}
	#endregion

	#region パラメータ
	/// <summary>
	/// パラメータエンティティクラス
	/// </summary>
	public class ConfigParameter : IEqualityComparer<ConfigParameter>
	{
		#region プロパティ
		#region 実体
		/// <summary>
		/// パラメータ行の実体
		/// </summary>
		private string _line = string.Empty;

		/// <summary>
		/// パラメータ行
		/// </summary>
		public string Line
		{
			get
			{
				// 更新されているか
				if (IsUpdate)
				{
					string line = string.Empty;

					// キーを持っているか
					if (Key.Length > 0)
					{
						var list = new List<string>() { Key, Delimiter, Value };

						line = string.Join(" ", list.ToArray());
					}

					// コメントを持っているか
					if (Comment.Length > 0)
					{
						if (line.Length > 0) line += " ";

						line += string.Format("{0} {1}", CommentSymbol, Comment);
					}

					return line;
				}

				return this._line;
			}
			set
			{
				this._line = value;
				IsUpdate = false;
				Parse();
			}
		}
		#endregion

		#region コンテナ
		#region キー
		/// <summary>
		/// キーの実体
		/// </summary>
		private string _key = string.Empty;

		/// <summary>
		/// キー
		/// </summary>
		public string Key
		{
			get
			{
				return this._key;
			}
			set
			{
				this._key = value;
				IsUpdate = true;
			}
		}
		#endregion

		#region 値
		/// <summary>
		/// 値の実体
		/// </summary>
		private string _value = string.Empty;

		/// <summary>
		/// 値
		/// </summary>
		public string Value
		{
			get
			{
				return IsQuoted ? this._value.Substring(1, this._value.Length - 2) : this._value;
			}
			set
			{
				this._value = value;
				IsUpdate = true;
			}
		}
		#endregion
		#endregion

		#region コメント
		/// <summary>
		/// コメントの実体
		/// </summary>
		public string _comment = string.Empty;

		/// <summary>
		/// コメント
		/// </summary>
		public string Comment
		{
			get
			{
				return this._comment;
			}
			protected set
			{
				this._comment = value;
				IsUpdate = true;
			}
		}
		#endregion

		/// <summary>
		/// デリミタ
		/// </summary>
		public string Delimiter { get { return Parser.Delimiter; } }

		/// <summary>
		/// コメント記号
		/// </summary>
		public string CommentSymbol { get { return Parser.CommentSymbol; } }

		/// <summary>
		/// パラメータの文字数
		/// </summary>
		public int Length { get { return Line.Length; } }

		/// <summary>
		/// 空行かどうか
		/// </summary>
		public bool IsEmptyLine { get { return Length == 0; } }

		/// <summary>
		/// コメント行かどうか
		/// </summary>
		public bool IsCommentLine { get { return Comment.Length > 0 && Key.Length == 0; } }

		#region 更新フラグ
		/// <summary>
		/// 更新フラグの実体
		/// </summary>
		private bool _isUpdate = false;

		/// <summary>
		/// 更新されているかどうか
		/// </summary>
		public bool IsUpdate
		{
			get { return this._isUpdate; }
			protected set { this._isUpdate = value; }
		}
		#endregion

		#region クォートフラグ
		/// <summary>
		/// 値がクォートされてるかどうか
		/// </summary>
		public bool IsQuoted
		{
			get { return this._value.StartsWith("\"") && this._value.EndsWith("\""); }
		}
		#endregion
		#endregion

		#region インスタンス変数定義
		/// <summary>
		/// パーサ
		/// </summary>
		protected ConfigParser Parser;
		#endregion

		#region コンストラクタ
		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="parser">パーサ</param>
		public ConfigParameter(ConfigParser parser)
		{
			Parser = parser;
		}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="parser">パーサ</param>
		/// <param name="line">パラメータ行データ</param>
		public ConfigParameter(ConfigParser parser, string line)
		{
			Parser = parser;
			Line = line;
		}
		#endregion

		#region パース
		/// <summary>
		/// パース
		/// </summary>
		protected void Parse()
		{
			var param = Line.Trim();

			// 空行
			if (param.Length == 0) return;

			// 行頭コメント
			if (param.StartsWith(CommentSymbol))
			{
				Comment = param.Substring(1).Trim();
				return;
			}

			var entries = param.Split(Delimiter.ToCharArray(), 2);

			// 不正なフォーマット(デリミタが見付からなかった)
			if (entries.Length < 2)
			{
				throw new ParseErrorException("デリミタが存在しません", Parser.LineNumber);
			}

			Key = entries[0].Trim();
			Value = entries[1].Trim();

			entries = Value.Split(CommentSymbol.ToCharArray(), 2);

			// TODO: ダブルクォートの中にコメント記号がある場合に対応

			if (entries.Length == 2)
			{
				Value = entries[0].Trim();
				Comment = entries[1].Trim();
			}
		}
		#endregion

		#region 文字列化
		/// <summary>
		/// 現在のパラメータ行を表す文字列を返します  
		/// </summary>
		/// <returns>現在のパラメータ行を表す文字列</returns>
		public override string ToString()
		{
			return Line;
		}
		#endregion

		#region IEqualityComparer<ConfigParameter> メンバ
		/// <summary>
		/// 指定したオブジェクトが等しいかどうかを判断します
		/// </summary>
		/// <param name="x">比較対象の第1オブジェクト</param>
		/// <param name="y">比較対象の第2オブジェクト</param>
		/// <returns></returns>
		public bool Equals(ConfigParameter x, ConfigParameter y)
		{
			return x.ToString().Equals(y.ToString());
		}

		/// <summary>
		/// 指定したオブジェクトのハッシュコードを返します
		/// </summary>
		/// <param name="obj">ハッシュコードが返される対象のオブジェクト</param>
		/// <returns>指定したオブジェクトのハッシュコード</returns>
		public int GetHashCode(ConfigParameter obj)
		{
			return obj.ToString().ToLower().GetHashCode();
		}
		#endregion
	}
	#endregion

	#region 例外
	/// <summary>
	/// 重複セクション例外
	/// </summary>
	public class DuplicateSectionException : Exception
	{
		public DuplicateSectionException()
		{
		}

		public DuplicateSectionException(string message)
			: base(message)
		{
		}

		protected DuplicateSectionException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public DuplicateSectionException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
	}

	/// <summary>
	/// パースエラー例外
	/// </summary>
	public class ParseErrorException : Exception
	{
		public override string Message
		{
			get
			{
				return string.Format("パース時に{0}行目でエラーが発生しました[{1}]", LineNumber, base.Message);
			}
		}

		public int LineNumber { get; protected set; }

		public ParseErrorException(string message, int lineNumber)
			: base(message)
		{
			LineNumber = lineNumber;
		}

		protected ParseErrorException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public ParseErrorException(string message, int lineNumber, Exception innerException)
			: base(message, innerException)
		{
			LineNumber = lineNumber;
		}
	}
	#endregion
}